/*-------------------------------------------------------------------------
 *
 * pg_range.c
 *	  支持pg_range关系操作的常规例程
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *	  src/backend/catalog/pg_range.c
 *
 *-------------------------------------------------------------------------
 */
#include "postgres.h"

#include "access/genam.h"
#include "access/htup_details.h"
#include "access/table.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_range.h"
#include "catalog/pg_type.h"
#include "utils/fmgroids.h"
#include "utils/rel.h"


/* 范围创建
 *		在 pg_range 中创建一个条目。
 */
void RangeCreate(Oid fc_rangeTypeOid, Oid fc_rangeSubType, Oid fc_rangeCollation,
			Oid fc_rangeSubOpclass, RegProcedure fc_rangeCanonical,
			RegProcedure fc_rangeSubDiff, Oid fc_multirangeTypeOid)
{
	Relation	pg_range;
	Datum		fc_values[Natts_pg_range];
	bool		fc_nulls[Natts_pg_range];
	HeapTuple	fc_tup;
	ObjectAddress fc_myself;
	ObjectAddress fc_referenced;
	ObjectAddress fc_referencing;
	ObjectAddresses *fc_addrs;

	pg_range = table_open(RangeRelationId, RowExclusiveLock);

	memset(fc_nulls, 0, sizeof(fc_nulls));

	fc_values[Anum_pg_range_rngtypid - 1] = ObjectIdGetDatum(fc_rangeTypeOid);
	fc_values[Anum_pg_range_rngsubtype - 1] = ObjectIdGetDatum(fc_rangeSubType);
	fc_values[Anum_pg_range_rngcollation - 1] = ObjectIdGetDatum(fc_rangeCollation);
	fc_values[Anum_pg_range_rngsubopc - 1] = ObjectIdGetDatum(fc_rangeSubOpclass);
	fc_values[Anum_pg_range_rngcanonical - 1] = ObjectIdGetDatum(fc_rangeCanonical);
	fc_values[Anum_pg_range_rngsubdiff - 1] = ObjectIdGetDatum(fc_rangeSubDiff);
	fc_values[Anum_pg_range_rngmultitypid - 1] = ObjectIdGetDatum(fc_multirangeTypeOid);

	fc_tup = heap_form_tuple(RelationGetDescr(pg_range), fc_values, fc_nulls);

	CatalogTupleInsert(pg_range, fc_tup);
	heap_freetuple(fc_tup);

	/* 记录类型对与范围相关项的依赖 */
	fc_addrs = new_object_addresses();

	ObjectAddressSet(fc_myself, TypeRelationId, fc_rangeTypeOid);

	ObjectAddressSet(fc_referenced, TypeRelationId, fc_rangeSubType);
	add_exact_object_address(&fc_referenced, fc_addrs);

	ObjectAddressSet(fc_referenced, OperatorClassRelationId, fc_rangeSubOpclass);
	add_exact_object_address(&fc_referenced, fc_addrs);

	if (OidIsValid(fc_rangeCollation))
	{
		ObjectAddressSet(fc_referenced, CollationRelationId, fc_rangeCollation);
		add_exact_object_address(&fc_referenced, fc_addrs);
	}

	if (OidIsValid(fc_rangeCanonical))
	{
		ObjectAddressSet(fc_referenced, ProcedureRelationId, fc_rangeCanonical);
		add_exact_object_address(&fc_referenced, fc_addrs);
	}

	if (OidIsValid(fc_rangeSubDiff))
	{
		ObjectAddressSet(fc_referenced, ProcedureRelationId, fc_rangeSubDiff);
		add_exact_object_address(&fc_referenced, fc_addrs);
	}

	record_object_address_dependencies(&fc_myself, fc_addrs, DEPENDENCY_NORMAL);
	free_object_addresses(fc_addrs);

	/* 记录多范围类型对范围类型的依赖 */
	fc_referencing.classId = TypeRelationId;
	fc_referencing.objectId = fc_multirangeTypeOid;
	fc_referencing.objectSubId = 0;
	recordDependencyOn(&fc_referencing, &fc_myself, DEPENDENCY_INTERNAL);

	table_close(pg_range, RowExclusiveLock);
}


/* 
 * 范围删除
 *		删除指定类型的 pg_range 条目。
 */
void RangeDelete(Oid fc_rangeTypeOid)
{
	Relation	pg_range;
	ScanKeyData fc_key[1];
	SysScanDesc fc_scan;
	HeapTuple	fc_tup;

	pg_range = table_open(RangeRelationId, RowExclusiveLock);

	ScanKeyInit(&fc_key[0],
				Anum_pg_range_rngtypid,
				BTEqualStrategyNumber, F_OIDEQ,
				ObjectIdGetDatum(fc_rangeTypeOid));

	fc_scan = systable_beginscan(pg_range, RangeTypidIndexId, true,
							  NULL, 1, fc_key);

	while (HeapTupleIsValid(fc_tup = systable_getnext(fc_scan)))
	{
		CatalogTupleDelete(pg_range, &fc_tup->t_self);
	}

	systable_endscan(fc_scan);

	table_close(pg_range, RowExclusiveLock);
}
